package cn.fatgod.learn.thymeleaf.binder;

import cn.fatgod.learn.thymeleaf.standard.enums.PermissionModifier;
import cn.fatgod.learn.thymeleaf.standard.interfaces.Bind;
import cn.fatgod.learn.thymeleaf.standard.interfaces.IDataBinder;
import cn.fatgod.learn.thymeleaf.standard.interfaces.Importable;
import cn.fatgod.learn.thymeleaf.standard.interfaces.Modifiable;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Bind
public class ModelDataBinder implements IDataBinder, Modifiable, Importable {
    /**
     * 是否启用
     */
    @Bind(false)
    private boolean isEnable = true;

    /**
     * 权限修饰符
     */
    private PermissionModifier modifier = PermissionModifier.PUBLIC;

    /**
     * 模型名称
     */
    private String name;

    /**
     * 模型注解列表
     */
    private final List<AnnotationDataBinder> annotations = new ArrayList<>();

    /**
     * 字段信息
     */
    private final List<FieldDataBinder> fields = new ArrayList<>();

    /**
     * 序列化标志
     */
    private boolean needSerialize;

    /**
     * 继承父类名称列表
     */
    private final List<String> extendList = new ArrayList<>();

    /**
     * 是否需要继承
     */
    private boolean needExtend;

    /**
     * 实现接口名称列表
     */
    private final List<String> implList = new ArrayList<>();

    /**
     * 是否需要实现
     */
    private boolean needImpl;

    /**
     * 导入路径列表
     */
    private final List<String> importPaths = new ArrayList<>();

    @Override
    public boolean isEnable() {
        return isEnable;
    }

    @Override
    public List<String> getImportPaths() {
        return Stream.concat(importPaths.stream(),
                        Stream.concat(this.annotations.stream().flatMap(ann -> ann.getImportPaths().stream())
                                , this.fields.stream().flatMap(fie -> fie.getImportPaths().stream())))
                .distinct()
                .collect(Collectors.toList());
    }

    @Override
    public PermissionModifier getModifier() {
        return modifier;
    }

    public ModelDataBinder setEnable(boolean enable) {
        isEnable = enable;
        return this;
    }

    public String getName() {
        return name;
    }

    public void setModifier(PermissionModifier modifier) {
        this.modifier = modifier;
    }

    public ModelDataBinder setName(String name) {
        this.name = name;
        return this;
    }

    public ModelDataBinder addAnnotation(AnnotationDataBinder binder) {
        this.annotations.add(binder);
        return this;
    }

    public ModelDataBinder addAnnotation(List<AnnotationDataBinder> binders) {
        this.annotations.addAll(binders);
        return this;
    }

    public List<AnnotationDataBinder> getAnnotations() {
        return annotations;
    }

    public ModelDataBinder addField(FieldDataBinder binder) {
        this.fields.add(binder);
        return this;
    }

    public ModelDataBinder addField(List<FieldDataBinder> binders) {
        this.fields.addAll(binders);
        return this;
    }

    public List<FieldDataBinder> getFields() {
        return fields;
    }

    public ModelDataBinder setNeedSerialize(boolean needSerialize) {
        this.needSerialize = needSerialize;
        if (this.needImpl && !needSerialize && CollUtil.isEmpty(this.implList)) {
            this.needImpl = false;
            return this;
        }
        if (!this.needImpl && needSerialize) {
            this.needImpl = true;
            return this;
        }
        return this;
    }

    public boolean isNeedSerialize() {
        return needSerialize;
    }

    public ModelDataBinder addExtend(String extendClass) {
        return this.addExtend(extendClass, StrUtil.EMPTY);
    }

    public ModelDataBinder addExtend(String extendClass, String importPath) {
        this.extendList.add(extendClass);
        if (StrUtil.isNotBlank(importPath)) {
            this.importPaths.add(importPath);
        }
        if (!needExtend) {
            this.needExtend = true;
        }
        return this;
    }

    public List<String> getExtendList() {
        return extendList;
    }

    public boolean isNeedExtend() {
        return needExtend;
    }

    public ModelDataBinder addImpl(String implClass) {
        return this.addImpl(implClass, StrUtil.EMPTY);
    }

    public ModelDataBinder addImpl(String implClass, String importPath) {
        this.implList.add(implClass);
        if (StrUtil.isNotBlank(importPath)) {
            this.importPaths.add(importPath);
        }
        if (!this.needImpl) {
            this.needImpl = true;
        }
        return this;
    }

    public List<String> getImplList() {
        return implList;
    }

    public boolean isNeedImpl() {
        return needImpl;
    }
}
